using System;
using System.Data;
using System.Reflection;
using System.Transactions;
using Oracle.ManagedDataAccess.Client;
using OracleInternal.Common;
using OracleInternal.ConnectionPool;
using OracleInternal.ServiceObjects;

namespace OracleInternal.MTS
{
	internal abstract class PSPEManager : PSPETxnManagerBase
	{
		internal static bool s_bUseDotNetAPIForPromotion;

		internal static string s_promotableMethodName;

		internal OracleConnectionImpl m_connImpl;

		protected ConnectionString m_connStr;

		protected Transaction m_sysTxn;

		protected MTSTxnRM m_mtsTxnRM;

		private MTSTxnBranch m_promotedTxnBranch;

		static PSPEManager()
		{
			s_bUseDotNetAPIForPromotion = false;
			s_promotableMethodName = "PromoteAndEnlistDurable";
			try
			{
				if (ConfigBaseClass.m_dtcUseDTCDLL)
				{
					s_bUseDotNetAPIForPromotion = false;
					return;
				}
				MethodInfo method = typeof(Transaction).GetMethod(s_promotableMethodName);
				if (method != null)
				{
					FWPSPEManager.InitPromoteAndEnlistMethod(method);
					s_bUseDotNetAPIForPromotion = true;
				}
				else
				{
					s_bUseDotNetAPIForPromotion = false;
				}
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268439552, OracleTraceClassName.PSPEManager, OracleTraceFuncName.cctor, ex);
				throw ex;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, OracleTraceTag.MTS, OracleTraceClassName.PSPEManager, OracleTraceFuncName.cctor, "Use New .Net API to Promote = " + s_bUseDotNetAPIForPromotion);
				}
			}
		}

		internal PSPEManager(OracleConnectionImpl connImpl, Transaction txn, MTSTxnRM txnRM, MTSTxnBranch txnBranch)
		{
			m_sysTxn = txn.Clone();
			m_localTxnIdentifier = m_sysTxn.TransactionInformation.LocalIdentifier;
			m_connImpl = connImpl;
			m_connStr = m_connImpl.m_cs;
			m_mtsTxnRM = txnRM;
			m_promotedTxnBranch = txnBranch;
		}

		internal abstract byte[] InternalPromote(out Guid txnGuid);

		internal abstract bool InternalCommit();

		internal abstract bool InternalRollback();

		internal abstract void InternalHandlePromoteError();

		internal abstract void InitialPSPEConn(Transaction txn, OracleConnectionImpl connImpl);

		internal abstract void ResetForPromotedTxn(OracleConnectionImpl connImpl, Transaction txn, string txnLocalId);

		internal static PSPEManager Create(OracleConnectionImpl connImpl, Transaction txn, MTSTxnRM txnRM, MTSTxnBranch txnBranch)
		{
			if (s_bUseDotNetAPIForPromotion)
			{
				return new CCPFWPSPEManager(connImpl, txn, txnRM, txnBranch);
			}
			return new CCPDTCPSPEManager(connImpl, txn, txnRM, txnBranch);
		}

		internal void ReleaseRM(ConnectionString cs)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)4352, OracleTraceClassName.PSPEManager, OracleTraceFuncName.ReleaseRM, "Local TxnID = " + m_sysTxn.TransactionInformation.LocalIdentifier + "\t ConnectionString = " + cs.m_constring);
			}
			string localIdentifier = m_sysTxn.TransactionInformation.LocalIdentifier;
			m_mtsTxnRM.ReleaseRPs(m_mtsTxnRM.m_connStrs, m_sysTxn);
			m_mtsTxnRM.ReleaseRP(cs, m_sysTxn);
			MTSProxyPool.ReleaseRM(m_mtsTxnRM.m_bIsCCP, m_mtsTxnRM.m_dbEasyConnectName, m_sysTxn);
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)4608, OracleTraceClassName.PSPEManager, OracleTraceFuncName.ReleaseRM, "Local TxnID = " + localIdentifier + "\t ConnectionString = " + cs.m_constring);
			}
		}

		public override void Initialize()
		{
			try
			{
				System.Data.IsolationLevel isolationLevel = System.Data.IsolationLevel.ReadCommitted;
				if (!ConfigBaseClass.m_bLegacyIsolationLevelBehavior && m_sysTxn.IsolationLevel == System.Transactions.IsolationLevel.Serializable)
				{
					isolationLevel = System.Data.IsolationLevel.Serializable;
				}
				OracleTransactionImpl localTxn = new OracleTransactionImpl(m_connImpl, isolationLevel);
				m_mtsTxnRM.m_bIgnoreIsolationLvl = true;
				m_connImpl.SetAutoCommit(bAutoCommitOn: false);
				if (m_connImpl.m_mtsTxnCtx == null)
				{
					m_connImpl.m_mtsTxnCtx = MTSTxnCtx.CreateMTSTxnCtx(m_connImpl);
				}
				m_connImpl.m_mtsTxnCtx.SetLocalCtx(m_sysTxn.TransactionInformation.LocalIdentifier, localTxn, m_connImpl.m_endUserSessionId);
				InitialPSPEConn(m_sysTxn, m_connImpl);
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268439552, OracleTraceClassName.PSPEManager, OracleTraceFuncName.Initialize, ex);
				m_mtsTxnRM.ReleaseRP(m_connStr, m_sysTxn);
				throw;
			}
		}

		public override byte[] Promote()
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)4352, OracleTraceClassName.PSPEManager, OracleTraceFuncName.Promote, "Local TxnID = " + m_sysTxn.TransactionInformation.LocalIdentifier + " using Conn ID = " + m_connImpl.m_endUserSessionId + " to DBInst = " + m_connImpl.m_instanceName);
			}
			byte[] array = null;
			try
			{
				array = InternalPromote(out var txnGuid);
				try
				{
					MTSRMManager.EnlistPromotedTransaction(m_connImpl, m_sysTxn, m_mtsTxnRM, m_promotedTxnBranch, txnGuid);
					m_bLocalTxnPromoted = true;
					if (ProviderConfig.m_bTraceLevelPrivate)
					{
						Trace.Write(OracleTraceLevel.Private, OracleTraceTag.MTS, OracleTraceClassName.PSPEManager, OracleTraceFuncName.Promote, " Releasing Connection with Conn ID = " + m_connImpl.m_endUserSessionId + " to DBInst = " + m_connImpl.m_instanceName + "\t TxnID = " + m_promotedTxnBranch.TxnID);
					}
					ResetForPromotedTxn(m_connImpl, m_sysTxn, m_sysTxn.TransactionInformation.LocalIdentifier);
					m_connImpl = null;
				}
				catch (Exception ex)
				{
					if (ProviderConfig.m_bTraceLevelPrivate)
					{
						Trace.Write(OracleTraceLevel.Private, OracleTraceTag.MTS, OracleTraceClassName.PSPEManager, OracleTraceFuncName.Promote, "PSPEManager.Promote(): Database Promotion Error for Local Txn ID = " + m_sysTxn.TransactionInformation.LocalIdentifier + " " + ex.Message + Environment.NewLine + " with Conn ID = " + m_connImpl.m_endUserSessionId + " to DBInst = " + m_connImpl.m_instanceName + "\t TxnID = " + m_promotedTxnBranch.TxnID);
					}
					InternalHandlePromoteError();
					array = new byte[1];
				}
				return array;
			}
			catch (Exception ex2)
			{
				try
				{
					OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268439552, OracleTraceClassName.PSPEManager, OracleTraceFuncName.Promote, ex2);
				}
				catch
				{
				}
				return new byte[1];
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)4608, OracleTraceClassName.PSPEManager, OracleTraceFuncName.Promote, "Local TxnID = " + m_sysTxn.TransactionInformation.LocalIdentifier + "TxnID = " + m_sysTxn.TransactionInformation.DistributedIdentifier.ToString());
				}
			}
		}

		public override void SinglePhaseCommit(SinglePhaseEnlistment singlePhaseEnlistment)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)4352, OracleTraceClassName.PSPEManager, OracleTraceFuncName.SinglePhaseCommit, "Local TxnID = " + m_sysTxn.TransactionInformation.LocalIdentifier + "\tTxnID = " + m_sysTxn.TransactionInformation.DistributedIdentifier.ToString());
			}
			try
			{
				if (!m_bLocalTxnPromoted)
				{
					try
					{
						try
						{
							if (m_connImpl.m_mtsTxnCtx != null && m_connImpl.m_mtsTxnCtx.m_txnType == MTSTxnType.Local)
							{
								if (ProviderConfig.m_bTraceLevelPrivate)
								{
									Trace.Write(OracleTraceLevel.Private, OracleTraceTag.MTS, OracleTraceClassName.PSPEManager, OracleTraceFuncName.SinglePhaseCommit, "Local transaction committing Local TxnID = " + m_sysTxn.TransactionInformation.LocalIdentifier + " using Conn ID = " + m_connImpl.m_endUserSessionId + " to DBInst = " + m_connImpl.m_instanceName);
								}
								OracleLogicalTransaction oracleLogicalTransaction = null;
								m_connImpl.m_mtsTxnCtx.m_localTxn.Commit(null, ref oracleLogicalTransaction);
							}
						}
						finally
						{
							try
							{
								m_connImpl.SetAutoCommit(bAutoCommitOn: true);
							}
							catch
							{
							}
							try
							{
								if (m_connImpl.m_mtsTxnCtx != null)
								{
									m_connImpl.ResetMTSTxnCtx();
								}
							}
							catch
							{
							}
						}
						singlePhaseEnlistment.Committed();
					}
					finally
					{
						try
						{
							if (ProviderConfig.m_bTraceLevelPrivate)
							{
								Trace.Write(OracleTraceLevel.Private, OracleTraceTag.MTS, OracleTraceClassName.PSPEManager, OracleTraceFuncName.SinglePhaseCommit, "PSPEManager.SinglePhasecommit(): Releasing Conn ID = " + m_connImpl.m_endUserSessionId + " to DBInst = " + m_connImpl.m_instanceName + "\tLocal TxnID " + m_sysTxn.TransactionInformation.LocalIdentifier);
							}
						}
						catch
						{
						}
						try
						{
							ResetForPromotedTxn(m_connImpl, m_sysTxn, m_sysTxn.TransactionInformation.LocalIdentifier);
						}
						catch
						{
						}
						try
						{
							ReleaseRM(m_connStr);
						}
						catch
						{
						}
						m_connImpl = null;
					}
					return;
				}
				try
				{
					if (InternalCommit())
					{
						singlePhaseEnlistment.Committed();
					}
					else
					{
						singlePhaseEnlistment.Aborted();
					}
				}
				finally
				{
					m_mtsTxnRM = null;
				}
			}
			catch (Exception ex)
			{
				try
				{
					OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268439552, OracleTraceClassName.PSPEManager, OracleTraceFuncName.SinglePhaseCommit, ex);
				}
				catch
				{
				}
				try
				{
					singlePhaseEnlistment.Aborted(ex);
				}
				catch
				{
				}
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)4608, OracleTraceClassName.PSPEManager, OracleTraceFuncName.SinglePhaseCommit, "Local TxnID = " + m_sysTxn.TransactionInformation.LocalIdentifier + "\tTxnID = " + m_sysTxn.TransactionInformation.DistributedIdentifier.ToString());
				}
			}
		}

		public override void Rollback(SinglePhaseEnlistment singlePhaseEnlistment)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)4352, OracleTraceClassName.PSPEManager, OracleTraceFuncName.Rollback, "Local TxnID = " + m_sysTxn.TransactionInformation.LocalIdentifier + "\tTxnID = " + m_sysTxn.TransactionInformation.DistributedIdentifier.ToString());
			}
			try
			{
				if (!m_bLocalTxnPromoted)
				{
					try
					{
						try
						{
							if (m_connImpl.m_mtsTxnCtx != null && m_connImpl.m_mtsTxnCtx.m_txnType == MTSTxnType.Local)
							{
								OracleLogicalTransaction oracleLogicalTransaction = null;
								m_connImpl.m_mtsTxnCtx.m_localTxn.Rollback(null, ref oracleLogicalTransaction);
							}
						}
						catch
						{
						}
						finally
						{
							try
							{
								m_connImpl.SetAutoCommit(bAutoCommitOn: true);
							}
							catch
							{
							}
							try
							{
								if (m_connImpl.m_mtsTxnCtx != null)
								{
									m_connImpl.ResetMTSTxnCtx();
								}
							}
							catch
							{
							}
						}
						if (ProviderConfig.m_bTraceLevelPrivate)
						{
							Trace.Write(OracleTraceLevel.Private, OracleTraceTag.MTS, OracleTraceClassName.PSPEManager, OracleTraceFuncName.Rollback, "Rolled back local transactionLocal TxnID = " + m_sysTxn.TransactionInformation.LocalIdentifier + "using Conn ID = " + m_connImpl.m_endUserSessionId + " to DBInst = " + m_connImpl.m_instanceName);
						}
						singlePhaseEnlistment.Aborted();
					}
					finally
					{
						try
						{
							if (ProviderConfig.m_bTraceLevelPrivate)
							{
								Trace.Write(OracleTraceLevel.Private, OracleTraceTag.MTS, OracleTraceClassName.PSPEManager, OracleTraceFuncName.Rollback, "PSPEManager.Rollback(): Releasing Conn ID = " + m_connImpl.m_endUserSessionId + " to DBInst = " + m_connImpl.m_instanceName + "\tLocal TxnID " + m_sysTxn.TransactionInformation.LocalIdentifier);
							}
						}
						catch
						{
						}
						try
						{
							ResetForPromotedTxn(m_connImpl, m_sysTxn, m_sysTxn.TransactionInformation.LocalIdentifier);
						}
						catch
						{
						}
						try
						{
							ReleaseRM(m_connStr);
						}
						catch
						{
						}
						m_connImpl = null;
					}
					return;
				}
				try
				{
					InternalRollback();
					if (ProviderConfig.m_bTraceLevelPrivate)
					{
						Trace.Write(OracleTraceLevel.Private, OracleTraceTag.MTS, OracleTraceClassName.PSPEManager, OracleTraceFuncName.Rollback, "PSPEManager.rollback(): DTC Transaction Rollback Local TxnID = " + m_sysTxn.TransactionInformation.LocalIdentifier + "\tTxnID = " + m_sysTxn.TransactionInformation.DistributedIdentifier.ToString());
					}
					singlePhaseEnlistment.Aborted();
				}
				finally
				{
					m_mtsTxnRM = null;
				}
			}
			catch (Exception ex)
			{
				try
				{
					OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268439552, OracleTraceClassName.PSPEManager, OracleTraceFuncName.Rollback, ex);
				}
				catch
				{
				}
				try
				{
					singlePhaseEnlistment.Aborted(ex);
				}
				catch
				{
				}
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)4608, OracleTraceClassName.PSPEManager, OracleTraceFuncName.Rollback, "Local TxnID = " + m_sysTxn.TransactionInformation.LocalIdentifier + "\tTxnID = " + m_sysTxn.TransactionInformation.DistributedIdentifier.ToString());
				}
			}
		}
	}
}
